package com.nali.dal.mongo.dao.general;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
import com.nali.dal.dao.general.IGeneralQueryDao;
import com.nali.dal.ds.IDataSource;
import com.nali.dal.ds.UsingDataSource;
import com.nali.dal.exception.TooManyResultException;
import com.nali.dal.expression.ExpressionDto;
import com.nali.dal.expression.ExpressionValue;
import com.nali.dal.expression.PropertyExpression;
import com.nali.dal.expression.query.Criteria;
import com.nali.dal.mongo.explain.query.Find;
import com.nali.dal.mongo.explain.query.PreparedFind;

public class MongoGeneralQueryDao implements IGeneralQueryDao, UsingDataSource<DB> {
	private DB db;
	
	public MongoGeneralQueryDao() {
		super();
	}

	public MongoGeneralQueryDao(IDataSource<DB> ds) {
		this(ds.getConnection());
	}

	public MongoGeneralQueryDao(DB db) {
		super();
		this.db = db;
	}

	@Override
	public void setDataSource(IDataSource<DB> ds) {
		this.db = ds.getConnection();		
	}

	@Override
	public long count(String collectionName, ExpressionDto<Criteria> dto) {
		List<ExpressionValue<Criteria>> crs = dto.getExpressionValues();
		List<PropertyExpression<Criteria>> pcs = dto.getPropertyExpressions();
		DBCollection collection = db.getCollection(collectionName);
		PreparedFind preparedFind = Find.parse(pcs, crs);
		try {
			return preparedFind.count(Collections.emptyList(), collection);
		} catch (Exception e) {
			throw ExceptionTraner.tranException(e);
		}
	}

	@Override
	public List<Map<String, Object>> queryForLimit(String collectionName, ExpressionDto<Criteria> dto, int offset, int limit) {
		List<ExpressionValue<Criteria>> crs = dto.getExpressionValues();
		List<PropertyExpression<Criteria>> pcs = dto.getPropertyExpressions();
		DBCollection collection = db.getCollection(collectionName);
		PreparedFind preparedFind = Find.parse(pcs, crs);
		try {
			return preparedFind.find(Collections.emptyList(), collection, offset, limit);
		} catch (MongoException e) {
			throw ExceptionTraner.tranException(e);
		}
	}

	@Override
	public List<Map<String, Object>> queryForList(String collectionName, ExpressionDto<Criteria> dto) {
		return queryForLimit(collectionName, dto, 0, 0);
	}

	@Override
	public Map<String, Object> queryForObject(String collectionName, ExpressionDto<Criteria> dto) {
		List<Map<String, Object>> list = queryForList(collectionName, dto);// TODO 可以在更底层支持
		if (list.size() > 1) {
			throw new TooManyResultException(list.size());
		}
		return list.size() == 0 ? null : list.get(0);
	}

	@Override
	public Map<String, Object> queryOne(String collectionName, ExpressionDto<Criteria> dto) {
		List<Map<String, Object>> list = queryForLimit(collectionName, dto, 0, 1);
		return list.size() == 0 ? null : list.get(0);
	}

}
